#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define MTEXTSIZE 128

struct msgbuf {
    long mtype;
    char mtext[MTEXTSIZE];
};

int main() {

    // 1.创建消息队列
    /*
        int msgget(key_t key, int msgflg);
        key: 通过ftok函数获取唯一标识
        msgflg: 
            IPC_CREAT: 不存在创建,存在获取
            IPC_CREAT+IPC_EXCL: 不存在创建,存在失败返回
            mode: 文件权限
        return int: 成功返回对应的msgid,失败返回-1并设置错误码
    */
    int msgid=msgget(IPC_PRIVATE,0666);
    if(msgid<0) {
        perror("msgget");
        exit(-1);
    }

    printf("msgget success msgid=%d\n\n",msgid);
    system("ipcs -q");

    // 2.往队列中插入
    /*
        int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
        msgsz: mtext的大小
        msgflg: 
            0: 阻塞
            IPC_NOWAIT: 非阻塞
    */
    struct msgbuf sendbuf;
    sendbuf.mtype=100;

    printf("please enter# ");  
    fflush(stdout);  
    read(0,sendbuf.mtext,MTEXTSIZE);
    msgsnd(msgid,&sendbuf,strlen(sendbuf.mtext),0);

    system("ipcs -q");
    sleep(10);

    // 3.从队列中删除
    /*
        ssize_t msgrcv(int msqid,void *msgp,size_t msgsz, long msgtyp,int msgflg);
        第一个参数msqid，表示消息队列的用户级标识符
        第二个参数msgp，表示获取到的数据块，是一个输出型参数
        第三个参数msgsz，表示要获取数据块的大小
        第四个参数msgtyp，表示要接收数据块的类型
    */
    struct msgbuf recvbuf;
    memset(&recvbuf,0,sizeof(recvbuf));

    ssize_t n=msgrcv(msgid,&recvbuf,sizeof(recvbuf.mtext),100,0);
    printf("recvbuf.type=%ld recvbuf.text=%s\n",recvbuf.mtype,recvbuf.mtext);

    system("ipcs -q");
    sleep(10);

    msgctl(msgid,IPC_RMID,NULL);
    system("ipcs -q");

    return 0;
}